package cn.starlightsoftware.sherly.config;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjUtil;
import cn.starlightsoftware.sherly.model.BaseModel;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusPropertiesCustomizer;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.apache.ibatis.reflection.MetaObject;
import org.mybatis.spring.annotation.MapperScan;
import cn.starlightsoftware.sherly.security.utils.SecurityUtil;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.util.Date;

/**
 * @author 谷子毅
 * @date 2024/4/25
 */
@Configuration
@MapperScan(value = "${sherly.info.base-package}" + ".db.mysql")
public class MybatisConfig {

    @Resource
    private TenantConfig tenantConfig;

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        // 分页插件： 因为使用了多数据源，所以去掉了数据库类型以免出错
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());

        // 动态表名插件：因为使用了多租户，所以需要动态拼接表名
        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
        dynamicTableNameInnerInterceptor.setTableNameHandler(((sql, tableName) -> {
            // 1.如果是公用表，直接拼上默认数据库名
            if (tenantConfig.getIgnoreTables().contains(tableName)) {
                return tenantConfig.getMainTenantCode() + "." + tableName;
            }
            // 2.如果指定了操作数据库，那么拼上指定的数据库名
            String operateTenantCode = SecurityUtil.getOperateTenantCode();
            if (operateTenantCode != null) {
                return operateTenantCode + "." + tableName;
            }
            // 3.否则拼上当前租户的数据库名
            return SecurityUtil.getTenantCode() + "." + tableName;
        }));
        interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);

        return interceptor;
    }

    @Bean
    public MybatisPlusPropertiesCustomizer mybatisPlusPropertiesCustomizer() {
        return properties -> {
            // 关闭banner打印
            GlobalConfig globalConfig = properties.getGlobalConfig();
            globalConfig.setBanner(false);
            // 枚举配置
            MybatisPlusProperties.CoreConfiguration configuration = new MybatisPlusProperties.CoreConfiguration();
            configuration.setDefaultEnumTypeHandler(MybatisEnumTypeHandler.class);
            properties.setConfiguration(configuration);
        };
    }

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer customizer() {
        // 枚举配置
        return builder -> builder.featuresToEnable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
    }

    @Bean
    public MetaObjectHandler createMetaObjectHandler() {
        // 自动填充
        return new MetaObjectHandler() {
            @Override
            public void insertFill(MetaObject metaObject) {
                if (ObjUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseModel) {
                    BaseModel BaseModel = (BaseModel) metaObject.getOriginalObject();
                    DateTime now = DateUtil.date();
                    if (ObjUtil.isNull(BaseModel.getCreateTime())) {
                        BaseModel.setCreateTime(now);
                    }
                    if (ObjUtil.isNotNull(SecurityUtil.getLoginUserId()) && ObjUtil.isNull(BaseModel.getCreateUserId())) {
                        BaseModel.setCreateUserId(SecurityUtil.getLoginUserId());
                    }
                    if (ObjUtil.isNull(BaseModel.getUpdateTime())) {
                        BaseModel.setUpdateTime(now);
                    }
                    if (ObjUtil.isNotNull(SecurityUtil.getLoginUserId()) && ObjUtil.isNull(BaseModel.getUpdateUserId())) {
                        BaseModel.setUpdateUserId(SecurityUtil.getLoginUserId());
                    }
                }
            }

            @Override
            public void updateFill(MetaObject metaObject) {
                if (ObjUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseModel) {
                    BaseModel BaseModel = (BaseModel) metaObject.getOriginalObject();
                    BaseModel.setUpdateTime(DateUtil.date());
                    BaseModel.setUpdateUserId(SecurityUtil.getLoginUserId());
                }
            }
        };
    }


}
